﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using Workflows.Components.Entities.Properties;

namespace Workflows.Components.Entities.Relations.DirectAssociations
{
    [Serializable]
    public class EntityLinkageComponent:WorkflowComponentBase
    {
        #region props
        private EntityLinkageInstruction _Instruction;
        /// <summary></summary>
        public override InstructionBase Instruction
        {
            get
            {
                return this._Instruction;
            }
            set
            {
                this._Instruction =(EntityLinkageInstruction) value;
            }
        }

        private EntityLinkageOutput _Output;
        /// <summary></summary>
        public override ResultBase Output
        {
            get
            {
                return this._Output;
            }
            set
            {
                this._Output =(EntityLinkageOutput) value;
            }
        }

        /// <summary></summary>
        public DataProviderType ParentDbProvider
        {
            get
            {
                return this._Instruction.ParentDbProvider;
            }
            set
            {
                this._Instruction.ParentDbProvider = value;
            }
        }

        /// <summary></summary>
        public string ParentConnStr
        {
            get
            {
                return this._Instruction.ParentConnStr;
            }
            set
            {
                this._Instruction.ParentConnStr = value;
            }
        }

        /// <summary></summary>
        public string ParentSql
        {
            get
            {
                return this._Instruction.ParentSql;
            }
            set
            {
                this._Instruction.ParentSql = value;
            }
        }

        /// <summary></summary>
        public string ParentKeyFieldName
        {
            get
            {
                return this._Instruction.ParentKeyFieldName;
            }
            set
            {
                this._Instruction.ParentKeyFieldName = value;
            }
        }

        /// <summary></summary>
        public DataProviderType ChildDbProvider
        {
            get
            {
                return this._Instruction.ChildDbProvider;
            }
            set
            {
                this._Instruction.ChildDbProvider = value;
            }
        }

        /// <summary></summary>
        public string ChildConnStr
        {
            get
            {
                return this._Instruction.ChildConnStr;
            }
            set
            {
                this._Instruction.ChildConnStr = value;
            }
        }

        /// <summary></summary>
        public string ChildSql
        {
            get
            {
                return this._Instruction.ChildSql;
            }
            set
            {
                this._Instruction.ChildSql = value;
            }
        }

        /// <summary></summary>
        public string ChildPKFieldName
        {
            get
            {
                return this._Instruction.ChildPKFieldName;
            }
            set
            {
                this._Instruction.ChildPKFieldName = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public string ChildFKFieldName
        {
            get
            {
                return this._Instruction.ChildFKFieldName;
            }
            set
            {
                this._Instruction.ChildFKFieldName = value;
            }
        }

        /// <summary></summary>
        public EntityReferenceType ReferenceType
        {
            get
            {
                return this._Instruction.ReferenceType;
            }
            set
            {
                this._Instruction.ReferenceType = value;
            }
        }

       
        /// <summary>
        /// default to 0.25
        /// similarity=Mth.Pow(1-hopfactor, hopCount)
        /// </summary>
        public double HopFactor
        {
            get
            {
                return this._Instruction.HopFactor;
            }
            set
            {
                this._Instruction.HopFactor = value;
            }
        }

        /// <summary>
        /// linkage distance is scaled to 2 and normalized to 1
        /// similarity = 1.0/(hopCount/2+1)
        /// </summary>
        public double LinkageSimilarityThreshold
        {
            get
            {
                return this._Instruction.LinkageSimilarityThreshold;
            }
            set
            {
                this._Instruction.LinkageSimilarityThreshold = value;
            }
        }

        /// <summary></summary>
        public DataProviderType TgtDbProvider
        {
            get
            {
                return this._Instruction.TgtDbProvider;
            }
            set
            {
                this._Instruction.TgtDbProvider = value;
            }
        }

        /// <summary></summary>
        public string TgtConnStr
        {
            get
            {
                return this._Instruction.TgtConnStr;
            }
            set
            {
                this._Instruction.TgtConnStr = value;
            }
        }

        /// <summary></summary>
        public string TgtTable
        {
            get
            {
                return this._Instruction.TgtTable;
            }
            set
            {
                this._Instruction.TgtTable = value;
            }
        }

        /// <summary></summary>
        public string TgtSrcKeyField
        {
            get
            {
                return this._Instruction.TgtSrcKeyField;
            }
            set
            {
                this._Instruction.TgtSrcKeyField = value;
            }
        }

        /// <summary></summary>
        public string TgtRefKeyField
        {
            get
            {
                return this._Instruction.TgtRefKeyField;
            }
            set
            {
                this._Instruction.TgtRefKeyField = value;
            }
        }

        /// <summary></summary>
        public string TgtLinkScoreField
        {
            get
            {
                return this._Instruction.TgtLinkScoreField;
            }
            set
            {
                this._Instruction.TgtLinkScoreField = value;
            }
        }
        #endregion

        public EntityLinkageComponent():base()
        {
            this.ComponentActivityType = WorkflowActivityType.SimpleActivity;
            this.ComponentCategory = WorkflowComponentCategory.Entity_Relations.ToString();
            this.ComponentName = "Linkage";
            this.Description = "Link two entities based on table relations: parent-child, common parent, shared child, self-ref";
            this.ComponentIcon = Resources.vdt80pui_1050;
            this.ComponentImage = Resources.DEPTLAN_JPG;

            this._Instruction = new EntityLinkageInstruction(
                this.ComponentID, Guid.Empty,
                DataProviderType.MSSQL, string.Empty, string.Empty, string.Empty,
                DataProviderType.MSSQL, string.Empty, string.Empty, string.Empty, string.Empty,
                EntityReferenceType.CommonParent,
                0.25, 0.5, DataProviderType.MSSQL, string.Empty, string.Empty,
                string.Empty, string.Empty, string.Empty);
            this._Output = new EntityLinkageOutput(
                this.ComponentID, Guid.Empty, 0, 0);
        }

        public override WorkflowComponentBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                EntityLinkageComponent component = base.Instantiate(xNode) as EntityLinkageComponent;

                // parent entity 
                component.ParentDbProvider = (DataProviderType)
                                            int.Parse(XmlDataUtil.GetAttributeValue(xNode, "ParentDbProvider",
                                                                                    ((int)DataProviderType.MSSQL).
                                                                                        ToString()));
                component.ParentConnStr = XmlDataUtil.GetAttributeValue(xNode, "ParentConnStr", "");
                component.ParentSql = XmlDataUtil.GetAttributeValue(xNode, "ParentSql", "");
                component.ParentKeyFieldName = XmlDataUtil.GetAttributeValue(xNode, "ParentKeyFieldName", "");

                // child entity
                component.ChildDbProvider =
                    (DataProviderType)int.Parse(XmlDataUtil.GetAttributeValue(
                                                     xNode, "ChildDbProvider", ((int)DataProviderType.MSSQL).ToString()));
                component.ChildConnStr = XmlDataUtil.GetAttributeValue(xNode, "ChildConnStr", "");
                component.ChildSql = XmlDataUtil.GetAttributeValue(xNode, "ChildSql", "");
                component.ChildPKFieldName = XmlDataUtil.GetAttributeValue(xNode, "ChildPKFieldName", "");
                component.ChildFKFieldName = XmlDataUtil.GetAttributeValue(xNode, "ChildFKFieldName", "");
               
                // ref type
                component.ReferenceType =
                    (EntityReferenceType)
                    int.Parse(XmlDataUtil.GetAttributeValue(
                                  xNode, "RefType",
                                  ((int)EntityReferenceType.CommonParent).ToString()));

              
                // score
                component.HopFactor = double.Parse(XmlDataUtil.GetAttributeValue(xNode, "HopFactor", "0.25"));
                component.LinkageSimilarityThreshold = double.Parse(
                    XmlDataUtil.GetAttributeValue(xNode, "LinkageThreshold", "0.25"));

                // output 
                component.TgtDbProvider =
                    (DataProviderType)
                    int.Parse(
                        XmlDataUtil.GetAttributeValue(xNode, "TgtDbProvider", ((int)DataProviderType.MSSQL).ToString()));
                component.TgtConnStr = XmlDataUtil.GetAttributeValue(xNode, "TgtConnStr", "");
                component.TgtTable = XmlDataUtil.GetAttributeValue(xNode, "TgtTable", "");
                component.TgtSrcKeyField = XmlDataUtil.GetAttributeValue(xNode, "TgtSrcKeyField", "");
                component.TgtRefKeyField = XmlDataUtil.GetAttributeValue(xNode, "TgtRefKeyField", "");
                component.TgtLinkScoreField = XmlDataUtil.GetAttributeValue(xNode, "TgtLinkScoreField", "");

                return component;
            }
            else
            {
                throw new Exception("Unable to instantiate email: invalid type specified in xml node");
            }
        }

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = base.Serialize(ref xDoc, ref parentNode);

            // parent meta data
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ParentDbProvider", ((int)this.ParentDbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ParentConnStr", this.ParentConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ParentSql", this.ParentSql);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ParentKeyFieldName", this.ParentKeyFieldName);

            // ref meta data 
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ChildDbProvider", ((int)this.ChildDbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ChildConnStr", this.ChildConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ChildSql", this.ChildSql);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ChildPKFieldName", this.ChildPKFieldName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ChildFKFieldName", this.ChildFKFieldName);


            // ref type
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "RefType", ((int)this.ReferenceType).ToString());

            // score
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "HopFactor", this.HopFactor.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "LinkageThreshold", this.LinkageSimilarityThreshold.ToString());

            // output 
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtDbProvider", ((int)this.TgtDbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtConnStr", this.TgtConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtTable", this.TgtTable);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtSrcKeyField", this.TgtSrcKeyField);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtRefKeyField", this.TgtRefKeyField);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtLinkScoreField", this.TgtLinkScoreField);

            return xNode;
        }
    }
}
